<template>
 <div class='scroll-wrap' ref="scrollWrap" @wheel.stop.prevent="scrollContent" :style="{height: scrollBoxHeight || '100%'}">
   <div class="scroll-content" ref="scrollContent" :style="{'top': contentTop + 'px'}">
     <slot></slot>
   </div>
   <div class="bar-wrap" v-if="showPortraitBar">
     <!-- 纵向滚动条 -->
    <div class="bar-track" :style="{
      'width': barWidth + 'px',
      'left': barTrackLeft,
      'background': trackBackground
    }">
      <div class='bar' :style="{
        'height': barHeight + 'px',
        'background': barBackground,
        'top': barTop + 'px'
        }"
        @mousedown.stop.prevent="mouseDownBar($event)"
      ></div>
    </div>
   </div>
 </div>
</template>

<script>
export default {
  props: {
    wrapHeight: {
      type: [String, Number]
    },
    barWidth: {
      type: Number,
      default: 6
    },
    barBackground: {
      type: String,
      default: '#000'
    },
    trackBackground: {
      type: String,
      default: '#444448'
    },
    isShowScroll: {
      type: Boolean
    },
    rollingRatio: {
      type: Number,
      default: 1
    }
  },
  data () {
    return {
      showPortraitBar: false,
      domWatcher: {},
      barTop: 0,
      contentTop: 0,
      wrapClientHeight: 0,
      contClientHeight: 0
    }
  },
  computed: {
    scrollBoxHeight () {
      if (this.wrapHeight) {
        return typeof this.wrapHeight === 'string'
          ? this.wrapHeight
          : this.wrapHeight + 'px'
      }
    },
    barHeight () {
      // 滑块高度document.documentElement.clientHeight*document.documentElement.clientHeight / wrap.offsetHeight+"px"
      return (this.wrapClientHeight * this.wrapClientHeight) / this.contClientHeight
    },
    barTrackLeft () {
      return `calc(100% - ${this.barWidth}px)`
    },
    conScrollHeight () {
      return this.contClientHeight - this.wrapClientHeight
    },
    barScrollHeight () {
      return this.wrapClientHeight - this.barHeight
    },
    ratioY () {
      // 滑动比例ratio = (scrollHeight - offsetHeight) / (offsetHeight - barHeight)
      // 假设文档总长 5000px，视口高度1080px，滚动条滑块高 40px，那么根据公式计算出比例值是 3.77。也就是说，滚动条每滚动 1px，视口就要下移 3.77px
      return this.conScrollHeight / this.barScrollHeight
    }
  },
  watch: {
    isShowScroll (val) {
      if (val) {
        this.isShowBar()
      }
    }
  },
  methods: {
    scrollContent (obj) {
      const scrollStep = this.rollingRatio * obj.deltaY
      if (this.showPortraitBar) {
        const condition = this.contentTop - scrollStep
        if (condition < -this.conScrollHeight) {
          this.contentTop = -this.conScrollHeight
          this.barTop = this.barScrollHeight
        } else if (condition < 0) {
          this.contentTop -= scrollStep
          this.barTop = Math.abs(this.contentTop) / this.ratioY
        } else {
          this.contentTop = this.barTop = 0
        }
      }
    },
    mouseDownBar (event) {
      const clientY = event.clientY
      const eleTop = this.barTop
      event.target.setCapture && event.target.setCapture() // 针对ie
      document.onmousemove = ev => {
        ev = ev || window.ev
        const condition = Math.round(eleTop + ev.clientY - clientY)
        if (condition < this.barScrollHeight && condition > -1) {
          this.barTop = eleTop + ev.clientY - clientY
        } else if (condition > this.barScrollHeight) {
          this.barTop = this.barScrollHeight
        } else {
          this.contentTop = this.barTop = 0
        }
        this.contentTop = -this.barTop * this.ratioY
      }
      document.onmouseup = () => {
        document.onmousemove = null
        document.releaseCapture && document.releaseCapture()
      }
    },
    // 判断是否显示滚动条
    isShowBar () {
      this.wrapClientHeight = this.$refs.scrollWrap.clientHeight
      this.contClientHeight = this.$refs.scrollContent.clientHeight
      if (this.wrapClientHeight < this.contClientHeight) {
        this.showPortraitBar = true
      } else {
        this.showPortraitBar = false
      }
    },
    // html5新增api。监听dom变动
    watchDom (dom) {
      // const domParent = dom.parentNode || dom.parentElement
      // const domHeight = window.getComputedStyle(domParent).height
      this.domWatcher = new MutationObserver(arr => {
        this.isShowBar()
      })
      this.domWatcher.observe(dom, {
        childList: true,
        subtree: true,
        attributesFilter: ['clientHeight']
      })
    }
  },
  mounted () {
    this.isShowBar()
    this.watchDom(this.$refs.scrollWrap)
    window.addEventListener('resize', this.isShowBar)
  },
  destroyed () {
    window.removeEventListener('resize', this.isShowBar)
    this.domWatcher.disconnect()
    this.domWatcher.takeRecords()
    this.domWatcher = null
  }
}
</script>

<style scoped>
.scroll-wrap {
  width: 100%;
  overflow: hidden;
  position: relative;
  -ms-overflow-style: none;
  overflow: -moz-scrollbars-none;
}
.scroll-wrap::-webkit-scrollbar {
  display: none;
}
.scroll-content {
  position: absolute;
  width: 100%;
}
/* .bar-wrap {
  display: none;
}
.scroll-wrap:hover .bar-wrap {
  display: block
} */
.bar-track {
  height: 100%;
  position: absolute;
  top: 0;
  cursor: pointer;
  opacity: 0.6;
  filter: alpha(opacity=10);
}
.bar {
  width: 100%;
  border-radius: 10px;
  position: absolute;
  opacity: 0.8;
  filter: alpha(opacity=80);
}
</style>
